/* packet-trmac.c
 * Routines for Token-Ring Media Access Control
 * Gilbert Ramirez <gram@verdict.uthscsa.edu>
 *
 * Ethereal - Network traffic analyzer
 * By Gerald Combs <gerald@unicom.net>
 * Copyright 1998 Gerald Combs
 *
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

#include "config.h"
#include <pcap.h>

#include <gtk/gtk.h>

#include <stdio.h>

#include "packet.h"
#include "ethereal.h"
#include "etypes.h"

struct vec_info {
	u_char	cmd;
	char	*text;
};

/* Major Vector */
static void
mv_text(u_char cmd, int offset, frame_data *fd, GtkWidget *tree) {
	int i=0;

	static struct vec_info	mv[] = {
		{ 0x00, "Response" },
		{ 0x02, "Beacon" },
		{ 0x03, "Claim Token" },
		{ 0x04, "Ring Purge" },
		{ 0x05, "Active Monitor Present" },
		{ 0x06, "Standby Monitor Present" },
		{ 0x07, "Duplicate Address Test" },
		{ 0x09, "Transmit Forward" },
		{ 0x0B, "Remove Ring Station" },
		{ 0x0C, "Change Parameters" },
		{ 0x0D, "Initialize Ring Station" },
		{ 0x0E, "Request Ring Station Address" },
		{ 0x0F, "Request Ring Station Address" },
		{ 0x10, "Request Ring Station Attachments" },
		{ 0x20, "Request Initialization" },
		{ 0x22, "Report Ring Station Address" },
		{ 0x23, "Report Ring Station State" },
		{ 0x24, "Report Ring Station Attachments" },
		{ 0x25, "Report New Active Monitor" },
		{ 0x26, "Report NAUN Change" },
		{ 0x27, "Report Poll Error" },
		{ 0x28, "Report Monitor Errors" },
		{ 0x29, "Report Error" },
		{ 0x2A, "Report Transmit Forward" },
		{ 0x00, NULL }
	};

	while (mv[i].text != NULL) {
		if (mv[i].cmd == cmd) {
			if (fd->win_info[0]) {
				/* I can do this because no higher-level dissect()
					will strcpy onto me. */
				fd->win_info[4] = mv[i].text;
			}
			if (tree) {
				add_item_to_tree(tree, offset, 1, "Major Vector Command: %s",
					mv[i].text);
			}
			return;
		}
		i++;
	}
	/* failure */
	add_item_to_tree(tree, offset, 1, "Major Vector Command: %02X (Unknown)",
		cmd);
}

/* Sub-vectors */
static int
sv_text(const u_char *pd, int pkt_offset, GtkWidget *tree)
{
	int	sv_length = pd[0];

	char *beacon[] = {"Recovery mode set", "Signal loss error",
		"Streaming signal not Claim Token MAC frame",
		"Streaming signal, Claim Token MAC frame"};

	add_item_to_tree(tree, pkt_offset, 1,
		"Subvector Length: %d bytes", sv_length);

	switch(pd[1]) {
		case 0x01: /* Beacon Type */
			add_item_to_tree(tree, pkt_offset+1, sv_length-1,
				"Beacon Type: %s", beacon[*((guint16*)&pd[2])] );
			break;

		case 0x02: /* NAUN */
			add_item_to_tree(tree, pkt_offset+1, sv_length-1,
				"NAUN: %s", ether_to_str((guint8*)&pd[2]));
			break;

		case 0x0B: /* Physical Location */
			add_item_to_tree(tree, pkt_offset+1, sv_length-1,
				"Physical Location: 0x%04X%08X",
					*((guint16*)&pd[2]), *((guint32*)&pd[4]));
			break;

		case 0x2D: /* Isolating Error Counts */
			add_item_to_tree(tree, pkt_offset+1, sv_length-1,
				"Isolating Error Counts: 0x%04X%08x", 
					*((guint16*)&pd[2]), *((guint32*)&pd[4]));
			break;

		case 0x2E: /* Non-Isolating Error Counts */
			add_item_to_tree(tree, pkt_offset+1, sv_length-1,
				"Non-Isolating Error Counts: 0x%04X%08x", 
					*((guint16*)&pd[2]), *((guint32*)&pd[4]));
			break;

		default: /* Unknown */
			add_item_to_tree(tree, pkt_offset+1, 1,
				"Unknown Sub-Vector: 0x%02X", pd[1]);
	}
	return sv_length;
}

void
dissect_trmac(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) {

	GtkWidget	*mac_tree = NULL, *ti;
	int			mv_length, sv_length, sv_offset;
	char		*class[] = { "Ring Station", "LLC Manager", "", "",
		"Configuration Report Server", "Ring Parameter Server",
		"Ring Error Monitor" };

	if (fd->win_info[0]) {
		strcpy(fd->win_info[3], "TR MAC");
	}

	mv_length = ntohs(*((guint16*)&pd[offset]));

	if (tree) {
		ti = add_item_to_tree(GTK_WIDGET(tree), offset, mv_length,
			"Media Access Control");
		mac_tree = gtk_tree_new();
		gtk_tree_item_set_subtree(GTK_TREE_ITEM(ti), mac_tree);
	}

	/* Interpret the major vector */
 	mv_text(pd[offset+3], offset+3, fd, mac_tree);

	if (tree) {
		add_item_to_tree(mac_tree, offset, 2, "Total Length: %d bytes",
			mv_length);
		add_item_to_tree(mac_tree, offset+2, 1, "Source Class: %s",
			class[ pd[offset+2] & 0x0f ]);
		add_item_to_tree(mac_tree, offset+2, 1, "Destination Class: %s",
			class[ pd[offset+2] >> 4 ]);

		/* interpret the subvectors */
		sv_offset = 0;
		offset += 4;
		sv_length = mv_length - 4;
		while (sv_offset < sv_length) {
			sv_offset += sv_text(&pd[offset + sv_offset], offset + sv_offset,
								mac_tree);
		}
	}
}
